import { DataTypes, Model, Optional, Sequelize, Association, BelongsToManyGetAssociationsMixin, BelongsToManyAddAssociationMixin, BelongsToManyRemoveAssociationMixin, BelongsToManyHasAssociationMixin, BelongsToManyCountAssociationsMixin, BelongsToManyCreateAssociationMixin } from 'sequelize';
import bcrypt from 'bcryptjs';
import { sequelize } from './index';
import { InterestTag } from './InterestTag';

export interface UserAttributes {
    id: string;
    username: string;
    email: string;
    password: string;
    avatar?: string;
    bio?: string;
    gender?: string;
    age?: number;
    birthDate?: Date;
    zodiacSign?: string;
    location?: string;
    tags?: InterestTag[];
    createdAt?: Date;
    updatedAt?: Date;
}

export interface UserCreationAttributes extends Optional<UserAttributes, 'id' | 'avatar' | 'bio' | 'gender' | 'age' | 'birthDate' | 'zodiacSign' | 'location' | 'createdAt' | 'updatedAt'> { }

export class User extends Model<UserAttributes, UserCreationAttributes> implements UserAttributes {
    public id!: string;
    public username!: string;
    public email!: string;
    public password!: string;
    public avatar!: string;
    public bio!: string;
    public gender!: string;
    public age!: number;
    public birthDate!: Date;
    public zodiacSign!: string;
    public location!: string;
    public readonly createdAt!: Date;
    public readonly updatedAt!: Date;

    // Associations
    public getInterestTags!: BelongsToManyGetAssociationsMixin<InterestTag>;
    public addInterestTag!: BelongsToManyAddAssociationMixin<InterestTag, number>;
    public removeInterestTag!: BelongsToManyRemoveAssociationMixin<InterestTag, number>;
    public hasInterestTag!: BelongsToManyHasAssociationMixin<InterestTag, number>;
    public countInterestTags!: BelongsToManyCountAssociationsMixin;
    public createInterestTag!: BelongsToManyCreateAssociationMixin<InterestTag>;

    public readonly interestTags?: InterestTag[];

    public static associations: {
        interestTags: Association<User, InterestTag>;
    };

    public async comparePassword(password: string): Promise<boolean> {
        return await bcrypt.compare(password, this.password);
    }

    public static associate(models: any) {
        User.belongsToMany(models.InterestTag, {
            through: 'user_interest_tags',
            foreignKey: 'userId',
            as: 'tags'
        });

        User.belongsToMany(models.User, {
            through: models.SocialRelation,
            foreignKey: 'userId',
            otherKey: 'targetId',
            as: 'following'
        });

        User.belongsToMany(models.User, {
            through: models.SocialRelation,
            foreignKey: 'targetId',
            otherKey: 'userId',
            as: 'followers'
        });
    }

    public async setTags(tagIds: string[]): Promise<void> {
        await sequelize.models.UserInterestTag.destroy({
            where: { userId: this.id }
        });
        await sequelize.models.UserInterestTag.bulkCreate(
            tagIds.map(tagId => ({
                userId: this.id,
                tagId
            }))
        );
    }

    public get tags(): InterestTag[] {
        const tags = this.getDataValue('tags');
        return Array.isArray(tags) ? tags : [];
    }
}

export const initUser = (sequelize: any) => {
    User.init(
        {
            id: {
                type: DataTypes.UUID,
                defaultValue: DataTypes.UUIDV4,
                primaryKey: true
            },
            username: {
                type: DataTypes.STRING,
                allowNull: false,
                unique: true
            },
            email: {
                type: DataTypes.STRING,
                allowNull: false,
                unique: true,
                validate: {
                    isEmail: true
                }
            },
            password: {
                type: DataTypes.STRING,
                allowNull: false
            },
            avatar: {
                type: DataTypes.STRING,
                allowNull: true
            },
            bio: {
                type: DataTypes.TEXT,
                allowNull: true
            },
            gender: {
                type: DataTypes.STRING,
                allowNull: true
            },
            age: {
                type: DataTypes.INTEGER,
                allowNull: true
            },
            birthDate: {
                type: DataTypes.DATE,
                allowNull: true
            },
            zodiacSign: {
                type: DataTypes.STRING,
                allowNull: true
            },
            location: {
                type: DataTypes.STRING,
                allowNull: true
            }
        },
        {
            sequelize,
            modelName: 'User',
            tableName: 'users',
            timestamps: true
        }
    );
};

export default User; 